package com.wys.spring.redis;

import com.wys.api.exception.BizException;
import com.wys.spring.ApplicationContextHolder;
import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.aop.MethodBeforeAdvice;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.data.redis.core.StringRedisTemplate;

import java.lang.reflect.Method;
import java.util.concurrent.TimeUnit;

public class RedisLockMethodInterceptor implements MethodInterceptor {


    private final StringRedisTemplate stringRedisTemplate;

    public RedisLockMethodInterceptor(StringRedisTemplate stringRedisTemplate) {
        this.stringRedisTemplate = stringRedisTemplate;
    }

    private static final Logger logger = LoggerFactory.getLogger(RedisLockMethodInterceptor.class);

    @Nullable
    @Override
    public Object invoke(@NotNull MethodInvocation invocation) throws Throwable {
        RedisLock redisLock = AnnotationUtils.findAnnotation(invocation.getMethod(), RedisLock.class);
        try {
            if (Boolean.TRUE.equals(stringRedisTemplate.hasKey(redisLock.name()))) {
                logger.error("<<<<<<<<redis lock name:{} is exist", redisLock.name());
                throw new BizException(stringRedisTemplate.boundValueOps(redisLock.name()).get());
            } else {
                if (redisLock.outTime() < 0) {
                    stringRedisTemplate.boundValueOps(redisLock.name()).set(redisLock.value());
                } else {
                    stringRedisTemplate.boundValueOps(redisLock.name()).set(redisLock.value(), redisLock.outTime(), TimeUnit.SECONDS);
                }
                logger.warn("init redis lock name:{} ", redisLock.name());
            }
            Object obj = invocation.proceed();
            stringRedisTemplate.delete(redisLock.name());
            return obj;
        } catch (BizException b) {
            throw b;
        } catch (Exception e) {
            logger.error("redis锁拦截异常:", e);
            stringRedisTemplate.delete(redisLock.name());
            return invocation.proceed();
        }
    }


}
